package com.beiding.dbrequest.server;

import io.netty.channel.ChannelHandlerContext;
import io.netty.util.AttributeKey;
import lombok.Getter;
import lombok.Setter;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 通道注册表
 * 非必须
 */
public class ChannelRegisterTable {

    @Setter
    @Getter
    private ChannelSelector defaultChannelSelector;

    public static final AttributeKey<String> NAME_KEY = AttributeKey.newInstance("name");

    private Map<String, ChannelGroup> groupMap = new ConcurrentHashMap<>();


    /**
     * 注册实例
     * @param ctx
     * @param name
     * @param metadata 实例元数据
     */
    public void register(ChannelHandlerContext ctx, String name, Map<String, ? extends Serializable> metadata) {

        ctx.channel().attr(NAME_KEY).set(name);
        ChannelGroup channelGroup = groupMap.get(name);
        if (channelGroup == null) {
            synchronized (this) {
                if ((channelGroup = groupMap.get(name)) == null) {
                    channelGroup = new ChannelGroup();
                    groupMap.put(name, channelGroup);
                }
            }
        }
        ChannelHolderForSelect channelHolder = new ChannelHolderForSelect();
        channelHolder.setChannelHandlerContext(ctx);
        channelHolder.setMetadata(metadata);
        channelGroup.getContexts().add(channelHolder);
    }

    public void destroy(ChannelHandlerContext ctx) {
        String name = ctx.channel().attr(NAME_KEY).get();
        ChannelGroup channelGroup = groupMap.get(name);
        if (channelGroup != null) {
            Iterator<ChannelHolderForSelect> iterator = channelGroup.getContexts().iterator();
            while (iterator.hasNext()) {
                ChannelHolderForSelect next = iterator.next();
                if (next.getChannelHandlerContext().equals(ctx)) {
                    ctx.close();
                    iterator.remove();
                }
            }
            if (channelGroup.getContexts().size() == 0) {
                synchronized (this) {
                    if (channelGroup.getContexts().size() == 0) {
                        groupMap.remove(name);
                    }
                }
            }
        }
    }

    public void destroyAll() {
        List<ChannelHandlerContext> all = new ArrayList<>();
        for (ChannelGroup group : groupMap.values()) {
            for (ChannelHolderForSelect channelHolder : group.getContexts()) {
                all.add(channelHolder.getChannelHandlerContext());
            }
        }
        for (ChannelHandlerContext context : all) {
            destroy(context);
        }
    }

    public ChannelHandlerContext getOne(String name) {
        return getOne(name, defaultChannelSelector);
    }


    /**
     * 自定义选择策略
     * @param name
     * @param channelSelector
     * @return
     */
    public ChannelHandlerContext getOne(String name, ChannelSelector channelSelector) {
        return channelSelector.getOne(groupMap,name);
    }

}
